package cn.tedu.lucky.draw.server.aspect;

import cn.tedu.lucky.draw.server.common.annotation.OperationLog;
import cn.tedu.lucky.draw.server.protocol.po.UserLog;
import cn.tedu.lucky.draw.server.service.IUserLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    @Autowired
    private IUserLogService userLogService;

    @Pointcut("@annotation(cn.tedu.lucky.draw.server.common.annotation.OperationLog)")
    public void doLog(){ }

    @Around("doLog()")
    public Object doLogAround(ProceedingJoinPoint joinPoint) throws Throwable{
        //初始状态
        int status=1;
        //初始错误信息
        String error=null;
        //耗时
        long time=0l;
        long t1=System.currentTimeMillis();
        try {
            Object result =joinPoint.proceed();//调用目标业务执行链
            long t2 = System.currentTimeMillis();
            time =t2-t1;
            return result;
        } catch (Throwable throwable) {
            long t3=System.currentTimeMillis();
            time=t3-t1;
            status=0;
            error=throwable.getMessage();
            throw  throwable;
        }finally {
            saveOperationLog(joinPoint,time,status,error);
        }

    }

    private void saveOperationLog(ProceedingJoinPoint joinPoint, long time, int status, String error) throws NoSuchMethodException, JsonProcessingException {
        //1.ip地址
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String ip = request.getRemoteAddr();
        //2.获取登陆用户
        String username="tedu";//这里先用一个默认用户名，后续获取实际登陆的用户信息
        //3.操作名称
        Class<?> targetCls = joinPoint.getTarget().getClass();
        MethodSignature ms = (MethodSignature)joinPoint.getSignature();
        //获取目标方法对象
        Method declaredMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        //获取方法上的注解
        OperationLog operationLog = declaredMethod.getAnnotation(OperationLog.class);
        String operation = operationLog.operation();
        //4.获取目标方法名称
        String method = targetCls.getName() + "." + declaredMethod.getName();
        //5.参数,ObjectMapper是jackson库的核心组件之一，负责将java对象转换成Json字符串
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        String params = objectMapper.writeValueAsString(joinPoint.getArgs());

        //6.封装用户行为日志对象
        UserLog userLog = new UserLog();
        userLog.setIp(ip);
        userLog.setUsername(username);
        userLog.setCreateTime(LocalDateTime.now());
        userLog.setOperation(operation);
        userLog.setMethod(method);
        userLog.setParams(params);
        userLog.setStatus(status);
        userLog.setTime(time);
        userLog.setError(error);
        userLogService.save(userLog);
    }
}
